import Tone from "../core/Tone";
import "../signal/WaveShaper";
import "../component/Merge";
import "../signal/Zero";
import "../component/Split";
import "../core/Gain";
import "../signal/Signal";
import "../core/Context";

if (Tone.supported && !Tone.global.AudioContext.prototype.createStereoPanner){

	/**
	 * @class Shimmed StereoPannerNode
	 * @param  {AudioContext} context
	 * @private
	 */
	var StereoPannerNode = function(context){

		/**
		 * The audio context
		 * @type {AudioContext}
		 */
		this.context = context;

		/**
		 * The left/right panning. [-1, 1]
		 * @type {AudioRange}
		 * @signal
		 */
		this.pan = new Tone.Signal(0, Tone.Type.AudioRange);

		/**
		 * Equal power scaling of the right gain
		 * @type {Tone.WaveShaper}
		 */
		var rightWaveShaper = new Tone.WaveShaper(function(val){
			return Tone.equalPowerScale((val+1)/2);
		}, 4096);

		/**
		 * Equal power scaling of the left gain
		 * @type {Tone.WaveShaper}
		 * @private
		 */
		var leftWaveShaper = new Tone.WaveShaper(function(val){
			return Tone.equalPowerScale(1 - (val+1)/2);
		}, 4096);

		/**
		 * The left gain value
		 * @type {Tone.Gain}
		 * @private
		 */
		var leftGain = new Tone.Gain();

		/**
		 * The right gain value
		 * @type {Tone.Gain}
		 * @private
		 */
		var rightGain = new Tone.Gain();

		/**
		 * Split the incoming signal
		 * @type {Tone.Split}
		 * @private
		 */
		var split = this.input = new Tone.Split();
		//fixes safari issue with splitting audio
		split._splitter.channelCountMode = "explicit";

		/**
		 * Keeps the waveshapers from optimizing 0s
		 * @type {Tone.Zero}
		 * @private
		 */
		var zero = new Tone.Zero();
		zero.fan(rightWaveShaper, leftWaveShaper);

		/**
		 * Merge the outgoing signal
		 * @type {Tone.Merge}
		 * @private
		 */
		var merge = this.output = new Tone.Merge();

		//connections
		split.left.chain(leftGain, merge.left);
		split.right.chain(rightGain, merge.right);
		this.pan.chain(leftWaveShaper, leftGain.gain);
		this.pan.chain(rightWaveShaper, rightGain.gain);
	};

	StereoPannerNode.prototype.disconnect = function(){
		this.output.disconnect.apply(this.output, arguments);
	};

	StereoPannerNode.prototype.connect = function(){
		this.output.connect.apply(this.output, arguments);
	};

	//add it to the AudioContext
	AudioContext.prototype.createStereoPanner = function(){
		return new StereoPannerNode(this);
	};
	Tone.Context.prototype.createStereoPanner = function(){
		return new StereoPannerNode(this);
	};
}

